home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ETO Development Tools 4
/
ETO Development Tools 4.iso
/
Tools - Objects
/
MacApp
/
MacApp 3.0a2
/
Libraries
/
UBusyCursor.cp
< prev
next >
Wrap
Text File
|
1991-05-01
|
14KB
|
435 lines
// UBusyCursor.cp
// Copyright © 1985-1991 Apple Computer, Inc. All rights reserved.
#ifndef __UBUSYCURSOR__
#include <UBusyCursor.h>
#endif
#ifndef __UFAILURE__
#include <UFailure.h>
#endif
#ifndef __UMEMORY__
#include <UMemory.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __TRAPS__
#include <Traps.h>
#endif
#ifndef __ULOMEM__
#include <ULoMem.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __RETRACE__
#include <Retrace.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
struct QElemWithA5
{
long OldA5; // A place to store the old value of A5 since
// when debugging the compiler trashes the
// value of A0 for any locals in the VBL task
// thus makeing the pointer to the
// paramblockrec unavailable
long A5; // The value of A5 will be stored here to be
// available at VBL time
VBLTask q; // vbl queue element for changing the cursor
};
struct CursorInfo
{
QElemWithA5 aQElemWithA5; // vbl queue elem. for changing the cursor
Boolean inColor; // Is the saved cursor in color?
Cursor origCursor; // Cursor at the time the busy cursor was put
// up, if not in color
CCrsrHandle origCCursor; // Cursor at the time the busy cursor was put
// up, if in color
short busyDelay; // time in 1/60 second before cursor changes
// to watch
Boolean inControl; // managed by MacApp; TRUE iff MacApp is in
// control(); if FALSE we don't change the
// cursor at all
Boolean changeToBusy; // if TRUE, we automagically switch to the
// busy cursor in the VBL task and switch to
// origCursor on a call to GetNextEvent or
// EventAvail(); applications can changed this
// as necessary
Boolean busyOn; // TRUE if the busy cursor on
Cursor currentCursor; // the current display cursor
AcurRsrcHandle cursorState; // the ‘acur’ resource
short animateDelay; // ticks before we spin the cursor
long timeoutCount; // spins before animation times out
long spinCount; // spins since last BusyAnimate call
};
typedef CursorInfo* CursorInfoPointer;
typedef CursorInfoPointer* CursorInfoHandle;
//--------------------------------------------------------------------------------------------------
const short kAcurRsrcID = 256;
//--------------------------------------------------------------------------------------------------
CursorInfo pCursorInfo;
TrapPatch pEAPatch; // patch for EventAvail
TrapPatch pGNEPatch; // patch for GetNextEvent
TrapPatch pICPatch; // patch for InitCursor
TrapPatch pSCCPatch; // patch for SetCCursor
TrapPatch pSCPatch; // patch for SetCursor
TrapPatch pSDPatch; // patch for StillDown under A/UX
TrapPatch pWMUPatch; // patch for WaitMouseUp under A/UX
//--------------------------------------------------------------------------------------------------
TBusyCursor* gBusyCursor;
//--------------------------------------------------------------------------------------------------
// #if qTrace
#pragma segment MABusyCursorRes
pascal void ResetBusyCursor(void)
{
long OldA5;
OldA5 = SetCurrentA5(); // ***** Called from trap patches *****
gBusyCursor->Reset(pCursorInfo.busyDelay);
SetA5(OldA5);
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
// must be in Main segment, and cannot call
// to any other segment because SetCursor is
// called from the ABusyTask VBL task
// The SetCCursor patch, used to remember the color cursor being set.
// Installed as a "Head" patch, meaning the original SetCCursor trap
// is called after this code has completed.
pascal void SetCMacAppCursor(CCrsrHandle theCCursor)
{
long OldA5;
OldA5 = SetCurrentA5(); // ***** Called from trap patches *****
gBusyCursor->TurnOff();
pCursorInfo.inColor = TRUE;
pCursorInfo.origCCursor = theCCursor; // Save a copy of the color cursor
SetA5(OldA5);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAInit
pascal void InitUBusyCursor(void)
{
gBusyCursor = NULL; // ??? should we still have initubusycursor?
gBusyCursor = new TBusyCursor; // Create the BusyCursor mechanism
gBusyCursor->IBusyCursor(); // Automatically sets gBusyCursor
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
// must be in Main segment, and cannot call
// to any other segment because SetCursor is
// called from the ABusyTask VBL task
// Patches SetCursor to remember the cursor being set. Installed as a
// "Head" patch, meaning the original SetCursor trap is called after
// this code has completed. Also called from InitMacAppCursor.
pascal void SetMacAppCursor(Cursor& theCursor)
{
long OldA5;
OldA5 = SetCurrentA5(); // ***** Called from trap patches *****
gBusyCursor->TurnOff();
// If we are setting the cursor to the busy cursor, then don't save it
if (&theCursor != &pCursorInfo.currentCursor)
{
pCursorInfo.inColor = FALSE;
pCursorInfo.origCursor = theCursor;
}
else
pCursorInfo.busyOn = TRUE; // because BusyTurnOff set it to FALSE
SetA5(OldA5);
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
// Called when the InitCursor trap is executed. After completion, we jump
// to the ROM InitCursor.
pascal void InitMacAppCursor(void)
{
long OldA5;
OldA5 = SetCurrentA5(); // ***** Called from trap patches *****
SetMacAppCursor(qd.arrow);
SetA5(OldA5);
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
pascal CursHandle NextAnimatedCursor(AcurRsrcHandle acurRsrc)
{
AcurRsrcRecord& whichAcurRsrc = **acurRsrc; // OK: it's locked down in InitAnimatedCursor
if (++whichAcurRsrc.whichCursor >= whichAcurRsrc.noOfCursors)
whichAcurRsrc.whichCursor = 0;
return whichAcurRsrc.cursors[whichAcurRsrc.whichCursor].Memory.h;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MABusyCursorRes
pascal void ABusyTask(void)
{
const short theOffset = sizeof(long) * 2;
CursorInfoPointer theCursorInfoPtr = (CursorInfoPointer)(GetParmBlockPtr() - theOffset);
// Set up application's A5 because the call to SetCursor assumes it && we need it to get pCursorInfo.
// Our A5 is prepended to the QElem which is pointed at by A0
pCursorInfo.aQElemWithA5.OldA5 = SetA5(theCursorInfoPtr->aQElemWithA5.A5);
// always Reset the vblCount
pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.busyDelay;
if (!GetCrsrBusy() && pCursorInfo.inControl && pCursorInfo.changeToBusy)
if (pCursorInfo.cursorState) // if we have an animated cursor
{
if (!pCursorInfo.busyOn)
pCursorInfo.spinCount = 0;
if (pCursorInfo.spinCount <= pCursorInfo.timeoutCount)
{
pCursorInfo.currentCursor = **NextAnimatedCursor(pCursorInfo.cursorState);
SetCursor(pCursorInfo.currentCursor);
pCursorInfo.spinCount = pCursorInfo.spinCount + 1;
}
pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.animateDelay;
}
else if (!pCursorInfo.busyOn)
SetCursor(pCursorInfo.currentCursor);
SetA5(pCursorInfo.aQElemWithA5.OldA5);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAInit
pascal void TBusyCursor::IBusyCursor(void)
{
UseROMMap(TRUE);
gBusyCursor = this;
// Setup the pCursorInfo record
pCursorInfo.inControl = TRUE; // we are in control during initialization
pCursorInfo.origCursor = qd.arrow;
pCursorInfo.busyDelay = kBusyDelay;
pCursorInfo.inColor = FALSE;
pCursorInfo.changeToBusy = TRUE;
pCursorInfo.busyOn = FALSE;
pCursorInfo.cursorState = this->InitAnimatedCursor(kAcurRsrcID);// init the animated cursor routine
if (pCursorInfo.cursorState)
pCursorInfo.currentCursor = **NextAnimatedCursor(pCursorInfo.cursorState);// get the first cursor
else
pCursorInfo.currentCursor = **GetCursor(watchCursor);
pCursorInfo.animateDelay = kAnimateDelay;
this->SetTimeout(kTicksBeforeTimeout); // NOTE: needs pCursorInfo.animateDelay
// Setup the VBL task
pCursorInfo.aQElemWithA5.q.qType = vType;
pCursorInfo.aQElemWithA5.q.vblAddr = &ABusyTask;
pCursorInfo.aQElemWithA5.q.vblCount = kBusyDelay;
pCursorInfo.aQElemWithA5.q.vblPhase = 0;
pCursorInfo.aQElemWithA5.A5 = (long)GetA5();
// This will make the A5 world available to the VBL task
// Patch the necessary traps
FailOSErr(Head1Patch(pSCPatch, _SetCursor, (Ptr) & SetMacAppCursor));// SetCursor
FailOSErr(HeadPatch(pICPatch, _InitCursor, (Ptr) & InitMacAppCursor));// InitCursor
if (qNeedsColorQD || gConfiguration.hasColorQD)
FailOSErr(Head1Patch(pSCCPatch, _SetCCursor, (Ptr) & SetCMacAppCursor));// SetCCursor
// Install the VBL task
FailOSErr(VInstall((QElemPtr) & pCursorInfo.aQElemWithA5.q));
// Patch the traps applicable
FailOSErr(HeadPatch(pGNEPatch, _GetNextEvent, (Ptr) & ResetBusyCursor));// GetNextEvent
FailOSErr(HeadPatch(pEAPatch, _EventAvail, (Ptr) & ResetBusyCursor));// EventAvail
if (gConfiguration.hasAUX)
{
FailOSErr(HeadPatch(pSDPatch, _StillDown, (Ptr) & ResetBusyCursor));// StillDown
FailOSErr(HeadPatch(pWMUPatch, _WaitMouseUp, (Ptr) & ResetBusyCursor));// WaitMouseUp
}
// Turn on busy cursor right now; init busyDelay
this->Delay(kBusyDelay);
this->ForceBusy();
}
//--------------------------------------------------------------------------------------------------
#pragma segment MATerminate
pascal void TBusyCursor::Free(void)
{
this->Reset(1); // Restore the non-busy cursor
// Remove the VBL task
VRemove((QElemPtr) & pCursorInfo.aQElemWithA5.q);
if (pCursorInfo.cursorState)
{
for (short i = 0; i < (*pCursorInfo.cursorState)->noOfCursors; ++i)
ReleaseResource((Handle)(*pCursorInfo.cursorState)->cursors[i].Memory.h);
pCursorInfo.cursorState = (AcurRsrcHandle)DisposeIfHandle((Handle)pCursorInfo.cursorState);
}
// Unpatch the patches
UnpatchTrap(pICPatch);
UnpatchTrap(pSCPatch);
if (qNeedsColorQD || gConfiguration.hasColorQD)
UnpatchTrap(pSCCPatch);
UnpatchTrap(pGNEPatch);
UnpatchTrap(pEAPatch);
if (gConfiguration.hasAUX)
{
UnpatchTrap(pSDPatch);
UnpatchTrap(pWMUPatch);
}
inherited::Free();
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
pascal void TBusyCursor::Reset(short delayTicks)
{
if (pCursorInfo.inControl && pCursorInfo.changeToBusy)
{
if (pCursorInfo.busyOn)
if (pCursorInfo.inColor)
SetCCursor(pCursorInfo.origCCursor);
else
SetCursor(pCursorInfo.origCursor);
pCursorInfo.aQElemWithA5.q.vblCount = delayTicks;
}
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
pascal void TBusyCursor::Activate(Boolean entering)
{
this->Reset(pCursorInfo.busyDelay);
pCursorInfo.inControl = entering;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MABusyCursorRes
pascal void TBusyCursor::Delay(short newDelay)
{
if (newDelay > 0) // save new delay time
{
pCursorInfo.busyDelay = newDelay;
this->Reset(newDelay); // reset timer
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment MABusyCursorRes
pascal void TBusyCursor::ForceBusy(void)
{
// trigger on next tick and reset timer
this->Reset(1);
}
//--------------------------------------------------------------------------------------------------
// if qTrace
#pragma segment MABusyCursorRes
// This is called from InitMacAppCursor, SetMacAppCursor and SetCMacAppCursor.
// It sets pCursorInfo fields to indicate that the cursor is not the
// busy cursor.
pascal void TBusyCursor::TurnOff(void)
{
if (pCursorInfo.inControl && pCursorInfo.changeToBusy)
{
pCursorInfo.busyOn = FALSE; // anyone that sets the busy cursor should set this TRUE explicitly
pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.busyDelay;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAInit
pascal AcurRsrcHandle TBusyCursor::InitAnimatedCursor(short acurRsrcId)
{
AcurRsrcHandle acurRsrc;
acurRsrc = (AcurRsrcHandle)GetResource('acur', acurRsrcId);
if (acurRsrc)
{
DetachResource((Handle)acurRsrc); // So Resource Mgr doesn't unlock it for us
MoveHHi((Handle)acurRsrc);
HLock((Handle)acurRsrc);
(*acurRsrc)->whichCursor = 0;
// Load each cursor in the sequence and lock them in memory
for (short i = 0; i < (*acurRsrc)->noOfCursors; ++i)
{
CursHandle theCursor = GetCursor((*acurRsrc)->cursors[i].Disk.rsrcId);// Get the cursor from the disk
FailNILResource((Handle)theCursor);
(*acurRsrc)->cursors[i].Memory.h = theCursor; // remember the cursor
DetachResource((Handle)theCursor); // So Resource Mgr doesn't unlock it for us
MoveHHi((Handle)theCursor);
HLock((Handle)theCursor); // Make sure it is locked
}
}
return acurRsrc;
}
//-------------------------------------------------------------------------------------
#pragma segment MABusyCursorRes
pascal void TBusyCursor::Animate(void)
{
pCursorInfo.spinCount = 0; // zero spins since we last heard from the app
}
//-------------------------------------------------------------------------------------
#pragma segment MABusyCursorRes
pascal void TBusyCursor::SetTimeout(long ticksBeforeTimeout)
{
pCursorInfo.timeoutCount = ticksBeforeTimeout / pCursorInfo.animateDelay;
pCursorInfo.spinCount = 0;
}